package net.kong.yumo.assa.config;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.sql.DataSource;
import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.transaction.jta.JtaTransactionManager;

import com.alibaba.druid.filter.logging.Slf4jLogFilter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.xa.DruidXADataSource;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.atomikos.jdbc.AtomikosSQLException;

import oracle.jdbc.xa.client.OracleXADataSource;

@Configuration
public class XatTDataSourceConfig {

	 private static Logger log = LoggerFactory.getLogger(XatTDataSourceConfig.class);

   
    /**
     * 数据源 mysql数据源 
     * @param env
     * @return
     * @throws Exception
     */
    @Bean(name = "ds1DataSource")
    public DataSource ds3DataSource(Environment env) throws Exception {
        
    	String prefix="spring.datasource.ds1.";
         AtomikosDataSourceBean ds = build(env, prefix);
        
		return ds;
    }
    /**
     * 数据源mysql 
     */
    @Bean(name = "ds3DataSource")
    public DataSource ds1DataSource(Environment env) throws Exception {
        
         String prefix="spring.datasource.ds3.";
         AtomikosDataSourceBean ds = build(env, prefix);
         
		return ds;
    }
    /**
     * 数据源sqlite
     * @param env
     * @return
     */
    @Bean(name = "ds2DataSource")
    public DataSource ds2DataSource(Environment env) {
 	   	String prefix="spring.datasource.ds2.";
 		try {
 			return this.buildDataSource(env.getProperty(prefix + "jdbcUrl"),env.getProperty(prefix+"driverClassName"), 
 					env.getProperty(prefix+"userName"), env.getProperty(prefix+"passWord"));
 		} catch (SQLException e) {
 			// TODO Auto-generated catch block
 			System.out.println("----------build2DataSource-----faile-"+e.getMessage());
 		}
  		return null;
    }
    @Bean(name = "ds4DataSource")
    public DataSource ds4DataSource(Environment env) {
 	   	String prefix="spring.datasource.ds3.";
 		try {
 			return this.buildDataSource(env.getProperty(prefix + "jdbcUrl"),env.getProperty(prefix+"driverClassName"), 
 					env.getProperty(prefix+"userName"), env.getProperty(prefix+"passWord"));
 		} catch (SQLException e) {
 			// TODO Auto-generated catch block
 			System.out.println("----------build2DataSource-----faile-"+e.getMessage());
 		}
  		return null;
    }
  
    //数据源自动切换
//    @Bean("dynamicDataSource")
    public DynamicDataSource dynamicDataSource(@Qualifier("ds1DataSource")DataSource dataSourceOne,
    		@Qualifier("ds3DataSource")DataSource dataSourceThr) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("one",dataSourceOne);
        targetDataSources.put("thr",dataSourceThr);
 
        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSources);
        dataSource.setDefaultTargetDataSource(dataSourceOne);
        return dataSource;
    } 
    
    /**
     * @Description 注入事物管理器
     * @param
     * @return org.springframework.transaction.jta.JtaTransactionManager
     * @throws
     * @date 2019/11/14 17:41
     */
    @Bean(name = "myJtaTransactionManager" )
  	 public JtaTransactionManager  regTransactionManager (@Qualifier("userTransactionImp") UserTransaction userTransaction ,@Qualifier("atomikosTransactionManager")TransactionManager transactionManager) throws NotSupportedException, SystemException {

  	        JtaTransactionManager xatx = new JtaTransactionManager();
  			xatx.setUserTransaction(userTransaction);
  			xatx.setTransactionManager(transactionManager);
//  			xatx.createTransaction("userTransactionImp", 300);

  	        return xatx;
  	    }

      @Bean(name = "userTransactionImp" )
      public UserTransaction userTransactionImp() throws Throwable {
          UserTransaction userTransaction = new UserTransactionImp();
          userTransaction.setTransactionTimeout(300);
          
          return userTransaction;
      } 
      @Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
      public TransactionManager atomikosTransactionManager() throws Throwable {
          UserTransactionManager userTransactionManager = new UserTransactionManager();
          userTransactionManager.setStartupTransactionService(false);
          userTransactionManager.setForceShutdown(true);
          
          return userTransactionManager;
      } 
    /**
     * @Description 配置读取通用的方法
     * @param env   环境
     * @param prefix    前缀
     * @return java.util.Properties
     * @throws
     * @date 2019/11/14 17:41
     */
   private AtomikosDataSourceBean build(Environment env, String prefix) throws Exception {
        Properties prop = new Properties();
        for(String p:env.getActiveProfiles ()) {
            System.out.println("------"+prefix+"-----getActiveProfiles-----------:"+p);
        }
        AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
     	DruidXADataSource XADataSource = new DruidXADataSource();
//      MysqlXADataSource XADataSource = new MysqlXADataSource();
//     	 OracleXADataSource XADataSource = new OracleXADataSource();

//       XADataSource.setURL( env.getProperty(prefix + "jdbcUrl"));
//       XADataSource.setServerName(env.getProperty(prefix + "userName"));
//       XADataSource.setPassword(env.getProperty(prefix + "passWord"));

///////////////////////////////druid///////////////////////////////////////
       XADataSource.setUrl( env.getProperty(prefix + "jdbcUrl")); 
       XADataSource.setUsername(env.getProperty(prefix + "userName"));
       XADataSource.setPassword(env.getProperty(prefix + "passWord"));
       XADataSource.setDriverClassName(env.getProperty(prefix + "driverClassName"));
       XADataSource.setInitialSize( env.getProperty(prefix + "initialSize", Integer.class));
       XADataSource.setMinIdle(  env.getProperty(prefix + "minIdle", Integer.class));
       XADataSource.setMaxWait( env.getProperty(prefix + "maxWait", Integer.class));
       XADataSource.setMaxActive(env.getProperty(prefix + "maxActive", Integer.class) );
       XADataSource.setTimeBetweenEvictionRunsMillis(env.getProperty(prefix + "timeBetweenEvictionRunsMillis", Integer.class) );
       XADataSource.setMinEvictableIdleTimeMillis( env.getProperty(prefix + "minEvictableIdleTimeMillis", Integer.class) );
       XADataSource.setValidationQuery( env.getProperty(prefix + "validationQuery") );
       XADataSource.setValidationQueryTimeout( env.getProperty(prefix + "validationQueryTimeout", Integer.class));
       XADataSource.setTestWhileIdle(  env.getProperty(prefix + "testWhileIdle", Boolean.class));
       XADataSource.setTestOnBorrow(  env.getProperty(prefix + "testOnBorrow", Boolean.class));
       XADataSource.setTestOnReturn(env.getProperty(prefix + "testOnReturn", Boolean.class) );
       XADataSource.setPoolPreparedStatements( env.getProperty(prefix + "poolPreparedStatements", Boolean.class));
       XADataSource.setMaxPoolPreparedStatementPerConnectionSize(  env.getProperty(prefix + "maxPoolPreparedStatementPerConnectionSize", Integer.class));
       XADataSource.setFilters(  env.getProperty(prefix + "filters"));
       XADataSource.setConnectionProperties(  env.getProperty(prefix + "connectionProperties"));
       XADataSource.setKeepAlive(true);
     	 
//        ds.setXaDataSourceClassName("oracle.jdbc.xa.client.OracleXADataSource");
//        ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
//        ds.setXaDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlXADataSource");
     	ds.setTestQuery("select 1 from dual");
	    ds.setUniqueResourceName("DataSource"+prefix.substring(prefix.length()-3, prefix.length()-1));
	    ds.setPoolSize(8);
       
//      druid.setTimeBetweenLogStatsMillis(300000);
//      两种配置Filter的方式，一种是配置filters属性，一种是配置proxyFilters属性。
//      filters和proxyFilters的配置是组合关系，而不是替换关系。mergeStat,wall,slf4j
	    XADataSource.setFilters("mergeStat,wall,slf4j");
      // 配置過濾器
      WallFilter wallFilter = new WallFilter();
      StatFilter statFilter = new StatFilter();
      Slf4jLogFilter slf4jLogFilter = new Slf4jLogFilter();
      wallFilter.setDbType("oracle");
      statFilter.setSlowSqlMillis(5000);
      statFilter.setLogSlowSql(true);
      statFilter.setMergeSql(true);
      slf4jLogFilter.setDataSourceLogEnabled(false);
      slf4jLogFilter.setConnectionLogEnabled(false);
      slf4jLogFilter.setConnectionLogErrorEnabled(true);
      slf4jLogFilter.setResultSetLogEnabled(false);
      slf4jLogFilter.setResultSetLogErrorEnabled(true);
      slf4jLogFilter.setStatementLogEnabled(false);
      slf4jLogFilter.setStatementExecutableSqlLogEnable(true);
      // SQL格式化
      slf4jLogFilter.setStatementSqlFormatOption(new SQLUtils.FormatOption(false, false));

      List filterList = new ArrayList();
//      filterList.add(wallFilter);
      filterList.add(statFilter);
      filterList.add(slf4jLogFilter);
      XADataSource.setProxyFilters(filterList);
//      缺省多个DruidDataSource的监控数据是各自独立的，
//      在Druid-0.2.17版本之后，支持配置公用监控数据，配置参数为useGlobalDataSourceStat
      XADataSource.setUseGlobalDataSourceStat(true);
      XADataSource.setRemoveAbandoned(true);
        try { 
        	XADataSource.init();
        	log.info("----------"+prefix+"------init----XADataSource-----success-----------------"+prefix.substring(prefix.length()-4, prefix.length()-1));
        	ds.setXaDataSource(XADataSource);

			ds.init();
			log.info("------------"+prefix+"----init-----ds2daglDataSource-----success-----------------");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			 	log.info("---------"+prefix+"-------init----ds2daglDataSource------faile-----------------"+e.getMessage());
			 	throw e;
		}
   		return ds;
    } 
     
    private DataSource buildDataSource(String jdbcUrl, String driver, String username, String password) throws SQLException {
        DruidDataSource druid = new DruidDataSource();
        druid.setUrl(jdbcUrl);
        druid.setDriverClassName(driver);
        druid.setUsername(username);
        druid.setPassword(password);
        druid.setInitialSize(1);
        druid.setMinIdle(1);;
        druid.setMaxActive(20);
        druid.setMaxWait(3 * 1000);
        druid.setTimeBetweenEvictionRunsMillis(60000);
        druid.setMinEvictableIdleTimeMillis(200000);
        druid.setConnectionErrorRetryAttempts(1);
        druid.setBreakAfterAcquireFailure(true);
        druid.setTestOnBorrow(true);
        druid.setTestWhileIdle(true);
        druid.setFailFast(true);
        druid.init();
        return druid;
    }
    /**
     * @Description 添加对druid的安全访问
     * @param
     * @return org.springframework.boot.web.servlet.ServletRegistrationBean
     * @throws
     * @date 2019/11/14 17:42
     */
    @Bean
    public ServletRegistrationBean druidServlet() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
        //控制台管理用户，加入下面2行 进入druid后台就需要登录
        servletRegistrationBean.addInitParameter("loginUsername", "admin");
        servletRegistrationBean.addInitParameter("loginPassword", "admin");
        return servletRegistrationBean;
    }

    /**
     * @Description
     * @param
     * @return org.springframework.boot.web.servlet.FilterRegistrationBean
     * @throws
     * @date 2019/11/14 17:42
     */
    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        filterRegistrationBean.addInitParameter("profileEnable", "true");
        return filterRegistrationBean;
    }

    @Bean
    public StatFilter statFilter(){
        StatFilter statFilter = new StatFilter();
        statFilter.setLogSlowSql(true); //slowSqlMillis用来配置SQL慢的标准，执行时间超过slowSqlMillis的就是慢。
        statFilter.setMergeSql(true); //SQL合并配置
        statFilter.setSlowSqlMillis(1000);//slowSqlMillis的缺省值为3000，也就是3秒。
        return statFilter;
    }

    @Bean
    public WallFilter wallFilter(){
        WallFilter wallFilter = new WallFilter();
        //允许执行多条SQL
        WallConfig config = new WallConfig();
        config.setMultiStatementAllow(true);
        wallFilter.setConfig(config);
        return wallFilter;
    } 
}
